(module mp23-soln
  (lib "eopl.ss" "eopl")
  (require "drscheme-init.scm") 
  (provide scan&parse value-of-aexp-string)  
  
  
  (define the-lexer
    '((whitespace (whitespace)            skip)
      (number     (digit (arbno digit)) number)
      (number     ("-" digit (arbno digit)) number)
      )
    ) 
  
  
  (define Arith-grammar
    '(
      (AExp 
       (operator "("  (separated-list AExp ","  ) ")")
       Composite-Exp)      
      (AExp (number) const-AExp)
      (operator ("*") Times-oper)
      (operator ("+") Plus-oper)
      (operator ("-") Diff-oper)
      (operator ("/") Div-oper)
      )
    )  
  
  
  
  
  ;; build a scanner with empty grammar 
  (define scan0 (sllgen:make-string-scanner the-lexer '()))
  
  ;; build data-types
  (sllgen:make-define-datatypes the-lexer Arith-grammar)
  
  ;; build scanner with grammar 
  (define just-scan
    (sllgen:make-string-scanner the-lexer Arith-grammar))
  
  ;; build parser 
  (define scan&parse 
    (sllgen:make-string-parser the-lexer Arith-grammar))
  
  ;; show the datatypes 
  (define show-the-datatypes 
    (lambda () (sllgen:show-define-datatypes the-lexer Arith-grammar)))
  
  (define exp1 "22")
  
  
  
  ;;value-of-aexp: AExp ==> number
  ;;usage: (value-of-aexp aexp)
  ;;purpose: Given a syntaxt tree produced by the above mentioned Grammar , 
  ;;         this preocedure evaluates the arithmatic expression 
  ;;         that is part of this Syntax Tree
  
  (define value-of-aexp
    (lambda(aexp)
      (cases AExp aexp
        (const-AExp(n) n)
        (Composite-Exp(op lst-ex2)
                      (cond
                        ((null? lst-ex2)  (empty-lst op))
                        (else
                         (val-help op ((get-oper op)
                                       (value-of-aexp (car lst-ex2) )
                                       (value-of-aexp (cadr lst-ex2))
                                       )
                                   (cddr lst-ex2)
                                   )
                         
                         )
                        )
                      )
        )
      )
    )

;;empty-lst: operator ==> value or ERROR
;;usage: (empty-lst op)
;;purpose: Gievn a data structure operator ,  this 
;;         procedure returns the value or error in certain cases. 
(define empty-lst
   (lambda (op)
     (cases operator op
        (Times-oper() 1)
        (Plus-oper()  0)
        (Diff-oper() (eopl:error "Bad Parameters to Diff-operator"))
        (Div-oper()  (eopl:error "Bad Parameters to Diff-operator"))
        )
      )
   )

  ;;val-help: operator number list: number
  ;;usage:(val-help op val lst-exp)
  ;;purpose: Given a operator , a number value and a list of Arith-Expressions , 
  ;;         This procedure evaluates the  value  of the whole expression. 
  (define val-help
    (lambda (op val1 lst-exp2)
      (cond
        ((null? lst-exp2) val1)
        (else 
         (val-help 
          op
          ((get-oper op) 
           val1 
           (value-of-aexp (car lst-exp2))
           )
          (cdr lst-exp2)
          )
         )
        )
      )
    )
  
  
  ;;get-oper: operator ==> operator-symbol
  ;;usage:(get-oper op)
  ;;purpose: Given an instance of the  datatype operator ,  
  ;; this procedure returns the  actual operator for that data-structure.
  ;;examples: Examples  given after the definition
  (define get-oper
    (lambda (op)
      (cases operator op
        (Times-oper() *)
        (Plus-oper()  +)
        (Diff-oper() -)
        (Div-oper()  /)
        )
      )
    )
  (define to (Times-oper))                        
  (define po (Plus-oper))
  (define dfo (Diff-oper))
  (define dio (Div-oper)) 
  ;;Examples:
  ;; (get-oper to) ==> #<primitive:*>
  ;;(get-oper po) ==> #<primitive:+>
  ;;(get-oper dfo) ==> #<primitive:->
  ;;(get-oper dio) ==> #<primitive:/>

  
  ;;value-of-aexp-string: string ==> number
  ;;usage:(value-of-aexp-string str)
  ;;purpose:Gievn a sting which has a Arithmetic Expression , 
  ;;  this  will convert that into an Arithmetic syntax tree and 
  ;;  then Evaluate the generated tree using the value-of-aexp procedure.
  ;;examples:  
  ;;(value-of-aexp-string "*(/(+(2,4) , 2), /(10,2))") ==> 15  
  ;;(value-of-aexp-string "*(2, /(10,2))") ==> 10
  ;;(value-of-aexp-string "*(2, +(3,2))") ==> 10
  ;; (value-of-aexp-string "22") ==> 22
  ;; (value-of-aexp-string "*(2,3)") ==> 6
  ;; (value-of-aexp-string "*(2,3,4)") ==> 24
  ;;  (value-of-aexp-string "*(2,3,4,5)") ==> 120
  ;;  (value-of-aexp-string "-(5,3,2)") ==> 0
  ;; (value-of-aexp-string "*(2, +(3,2))") ==> 10
  ;; (value-of-aexp-string "*(2, +(3,2,3))") ==> 16
  ;; (value-of-aexp-string "*(2,3, +(3,2,3))") ==> 48
  ;; (value-of-aexp-string "*(2,-(7,3), +(3,2,3))") ==> 64
  ;;(value-of-aexp-string "*()") ==> 1
  ;;(value-of-aexp-string "+()") ==> 0
  ;;(value-of-aexp-string "-()") ==> Bad Parameters to Diff-operator
  ;;(value-of-aexp-string "/()") ==>  Bad Parameters to Diff-operator

  
  (define value-of-aexp-string 
    (lambda(str)
      (value-of-aexp (scan&parse str)
                     )
      )
    )
  
  
  
  )